package cluster

import (
	"math"
	"sort"
)

// Int64Slice 用于sort排序
type Int64Slice []int64

func (that Int64Slice) Len() int {
	return len(that)
}

// Less 从小到大排序
func (that Int64Slice) Less(i, j int) bool {
	return that[i] < that[j]
}

// Swap 排序交换
func (that Int64Slice) Swap(i, j int) {
	that[i], that[j] = that[j], that[i]
}

type ConsistentHash struct {
	// 节点hash值 -- 用于查找dataKey落在哪个顺时针节点上
	nodeHashSlc Int64Slice
	// 节点hashMap -- key:hash, value:节点地址(ip:port)
	hashKeyNodeAddrMap map[int64]string
}

func MakeConsistentHash() *ConsistentHash {
	return &ConsistentHash{
		nodeHashSlc:        make([]int64, 0, 0),
		hashKeyNodeAddrMap: make(map[int64]string),
	}
}

// AddNode 添加节点
func (this *ConsistentHash) AddNode(nodeAddr string) {
	nodeHash := hash(nodeAddr)
	this.hashKeyNodeAddrMap[nodeHash] = nodeAddr
	this.nodeHashSlc = append(this.nodeHashSlc, nodeHash)
	sort.Sort(this.nodeHashSlc)
}

// PickNode 挑选节点 -- 计算dataKey落的节点(顺时针最近的节点)
func (this *ConsistentHash) PickNode(dataKey string) string {
	keyHash := hash(dataKey)
	hashIndex := sort.Search(len(this.nodeHashSlc), func(i int) bool {
		return this.nodeHashSlc[i] >= keyHash
	})
	if hashIndex >= len(this.nodeHashSlc) {
		hashIndex = 0
	}
	pickNodeHash := this.nodeHashSlc[hashIndex]
	return this.hashKeyNodeAddrMap[pickNodeHash]
}

// hash计算
func hash(str string) int64 {
	strSlc := []rune(str)
	p := 16777619
	hash := 2166136261
	for i := 0; i < len(strSlc); i++ {
		hash = (hash ^ int(strSlc[i])) * p
	}
	hash += hash << 13
	hash ^= hash >> 7
	hash += hash << 3
	hash ^= hash >> 17
	hash += hash << 5
	if hash < 0 {
		return int64(math.Abs(float64(hash)))
	}
	return int64(hash)
}
